package com.i360day.invoker;

import com.i360day.invoker.common.StringUtils;
import com.i360day.invoker.http.Request;
import com.i360day.invoker.support.RemoteInvocation;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.*;

/**
 * <p> @description:   <p>
 *
 * <p> @author: 青牛.胡 <p>
 *
 * <p> @date: 2019/6/22 0022  10:47<p>
 **/
public class RequestTemplate {
    private String uri;
    private BodyTemplate bodyTemplate;
    private Class<?> serviceInterface;
    private MethodMetadata methodMetadata;
    private transient Charset charset = Charset.forName("UTF-8");
    private final Map<String, Collection<String>> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);


    private RequestTemplate(String uri, Class<?> serviceInterface, MethodMetadata methodMetadata, BodyTemplate bodyTemplate) throws IOException {
        this.serviceInterface = serviceInterface;
        this.methodMetadata = methodMetadata;
        this.bodyTemplate = bodyTemplate;
        this.uri = uri;
//        addHeader("Content-Length", String.valueOf(bodyTemplate.getSize()));
//        addHeader("Accept-Language", "zh-CN,zh;q=0.9");
    }

    public RequestTemplate addHeaders(String name, String value) {
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) return this;
        return addHeader(name, value);
    }

    public RequestTemplate addHeader(String key, String value) {
        Collection<String> values = headers.get(key);
        if (values == null) {
            values = new ArrayList<>();
        }
        values.add(value);
        headers.put(key, values);
        return this;
    }

    public RequestTemplate setContentType(String contentType) {
        addHeader("Content-type", contentType);
        return this;
    }

    public static RequestTemplate of(String uri, Class<?> serviceInterface, MethodMetadata methodMetadata, BodyTemplate bodyTemplate) throws IOException {
        return new RequestTemplate(uri, serviceInterface, methodMetadata, bodyTemplate);
    }

    public static RequestTemplate of(String uri, Class<?> serviceInterface, MethodInvocation invocation, RemoteInvocation remoteInvocation) throws IOException {
        return new RequestTemplate(uri, serviceInterface, MethodMetadata.of(invocation), ObjectBodyTemplate.of(remoteInvocation));
    }

    public static RequestTemplate of(String uri, Class<?> serviceInterface, MethodMetadata methodMetadata, RemoteInvocation remoteInvocation) throws IOException {
        return new RequestTemplate(uri, serviceInterface, methodMetadata, ObjectBodyTemplate.of(remoteInvocation));
    }

    public Request convertRequest() {
        return Request.of(URI.create(getUri()), this);
    }

    public Class<?> getServiceInterface() {
        return serviceInterface;
    }

    public Map<String, Collection<String>> getHeaders() {
        return Collections.unmodifiableMap(headers);
    }

    public String getHeader(String name) {
        Collection<String> values = Collections.unmodifiableMap(headers).get(name);
        return values.iterator().next();
    }

    public Collection<String> getHeaders(String name) {
        return Collections.unmodifiableMap(headers).get(name);
    }

    public Charset getCharset() {
        return charset;
    }

    public MethodMetadata getMethodMetadata() {
        return methodMetadata;
    }

    public BodyTemplate getBodyTemplate() {
        return bodyTemplate;
    }

    public String getUri() {
        return uri;
    }

    /**
     * copy token default Authorization key
     *
     * @return
     */
    public boolean copyAuthorizationToken() {
        return copyAuthorizationToken("Authorization");
    }

    /**
     * copy token
     *
     * @param tokenKey 指定头字段
     * @return
     */
    public boolean copyAuthorizationToken(String tokenKey) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes servletWebRequest) {
            String value = servletWebRequest.getRequest().getHeader(tokenKey);
            if (StringUtils.isNotEmpty(value)) {
                addHeader(tokenKey, value);
                return true;
            }
        }
        return false;
    }
}
